package test.cert;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.math.BigInteger;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.PrivateKey;
import java.security.SecureRandom;
import java.security.Security;
import java.security.SignatureException;
import java.security.UnrecoverableKeyException;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.security.spec.RSAKeyGenParameterSpec;
import java.util.Calendar;
import java.util.Date;
import java.util.Hashtable;
import java.util.Vector;

import org.bouncycastle.asn1.DERBMPString;
import org.bouncycastle.asn1.DERObjectIdentifier;
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
import org.bouncycastle.asn1.x509.BasicConstraints;
import org.bouncycastle.asn1.x509.KeyUsage;
import org.bouncycastle.asn1.x509.X509Extensions;
import org.bouncycastle.asn1.x509.X509Name;
import org.bouncycastle.jce.X509Principal;
import org.bouncycastle.jce.interfaces.PKCS12BagAttributeCarrier;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.x509.X509V3CertificateGenerator;
import org.bouncycastle.x509.extension.AuthorityKeyIdentifierStructure;
import org.bouncycastle.x509.extension.SubjectKeyIdentifierStructure;

/**
 * 子证书生成器
 * @author shawn
 *
 */
@SuppressWarnings("deprecation")
public class SubCertGen
{
	/**
	 * @param args
	 * @throws NoSuchProviderException 
	 * @throws KeyStoreException 
	 * @throws IOException 
	 * @throws CertificateException 
	 * @throws NoSuchAlgorithmException 
	 * @throws InvalidAlgorithmParameterException 
	 * @throws SignatureException 
	 * @throws IllegalStateException 
	 * @throws InvalidKeyException 
	 * @throws UnrecoverableKeyException 
	 */
	public static void main(String[] args) throws KeyStoreException, NoSuchProviderException, NoSuchAlgorithmException, CertificateException, IOException, InvalidAlgorithmParameterException, InvalidKeyException, IllegalStateException, SignatureException, UnrecoverableKeyException
	{
		//	注册提供商
		Security.addProvider(new BouncyCastleProvider());

		//	读取发行者信息
		File file = new File(CertGen.class.getResource("").getPath() + "NookInfo.pfx");
		InputStream is = new FileInputStream(file);
		KeyStore ks = KeyStore.getInstance("PKCS12", BouncyCastleProvider.PROVIDER_NAME);
		ks.load(is, "123456".toCharArray());
		X509Certificate caCert = (X509Certificate) ks.getCertificate("Nook Info");
		PrivateKey caPrivateKey = (PrivateKey) ks.getKey("Nook Info", "123456".toCharArray());

		//	设置签名对象信息
		Hashtable<DERObjectIdentifier, String> subjectTable = new Hashtable<DERObjectIdentifier, String>();
		subjectTable.put(X509Principal.CN, "Sub Info");
		subjectTable.put(X509Principal.OU, "www.abettor.org");
		subjectTable.put(X509Principal.O, "Abettor Zhang");
		subjectTable.put(X509Principal.L, "Nankai");
		subjectTable.put(X509Principal.ST, "Tianjin");
		subjectTable.put(X509Principal.C, "CN");
		subjectTable.put(X509Principal.E, "4b3tt0r@gmail.com");
		Vector<DERObjectIdentifier> subjectOrder = new Vector<DERObjectIdentifier>();
		subjectOrder.add(X509Principal.CN);
		subjectOrder.add(X509Principal.OU);
		subjectOrder.add(X509Principal.O);
		subjectOrder.add(X509Principal.L);
		subjectOrder.add(X509Principal.ST);
		subjectOrder.add(X509Principal.C);
		subjectOrder.add(X509Principal.E);
		X509Name subject = new X509Name(subjectOrder, subjectTable);

		//	计算有效期
		Calendar cal = Calendar.getInstance();
		Date validTime = cal.getTime();
		cal.add(Calendar.YEAR, 5);
		Date expireTime = cal.getTime();

		//	根据指定算法生成密钥对
		KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA", BouncyCastleProvider.PROVIDER_NAME);
		kpg.initialize(new RSAKeyGenParameterSpec(1024, RSAKeyGenParameterSpec.F4), new SecureRandom());
		KeyPair keyPair = kpg.generateKeyPair();

		X509V3CertificateGenerator cg = new X509V3CertificateGenerator();
		cg.setIssuerDN(caCert.getIssuerX500Principal());
		cg.setNotAfter(expireTime);
		cg.setNotBefore(validTime);
		cg.setPublicKey(keyPair.getPublic());
		cg.setSerialNumber(BigInteger.valueOf(System.currentTimeMillis()));
		cg.setSignatureAlgorithm("SHA1withRSA");
		cg.setSubjectDN(subject);
		cg.addExtension(X509Extensions.BasicConstraints, true, new BasicConstraints(false));
		cg.addExtension(X509Extensions.SubjectKeyIdentifier, false, new SubjectKeyIdentifierStructure(keyPair.getPublic()));
		cg.addExtension(X509Extensions.AuthorityKeyIdentifier, false, new AuthorityKeyIdentifierStructure(caCert.getPublicKey()));
		cg.addExtension(X509Extensions.KeyUsage, false, new KeyUsage(KeyUsage.dataEncipherment | KeyUsage.digitalSignature | KeyUsage.keyAgreement | KeyUsage.keyEncipherment | KeyUsage.nonRepudiation));

		//	生成并验证证书
		X509Certificate cert = cg.generate(caPrivateKey, new SecureRandom());
		PKCS12BagAttributeCarrier bagCarrier = (PKCS12BagAttributeCarrier) cert;
		bagCarrier.setBagAttribute(PKCSObjectIdentifiers.pkcs_9_at_friendlyName, new DERBMPString(subjectTable.get(X509Principal.CN)));
		bagCarrier.setBagAttribute(PKCSObjectIdentifiers.pkcs_9_at_localKeyId, new SubjectKeyIdentifierStructure(keyPair.getPublic()));
		System.out.print(cert);
		cert.checkValidity();
		cert.verify(caCert.getPublicKey());

		//	保存证书（私钥）
		file = new File(CertGen.class.getResource("").getPath() + "SubInfo.pfx");
		if(file.exists())
		{
			file.delete();
		}
		file.createNewFile();
		OutputStream os = new FileOutputStream(file);
		ks = KeyStore.getInstance("PKCS12", BouncyCastleProvider.PROVIDER_NAME);
		ks.load(null);
		ks.setKeyEntry("Sub Info", keyPair.getPrivate(), "123456".toCharArray(), new Certificate[]{cert, caCert});
		ks.store(os, "123456".toCharArray());
		os.close();
	}
}
